package io.adrainty.bolee.security.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.adrainty.bolee.framework.commons.basic.ResponseCode;
import io.adrainty.bolee.framework.commons.basic.TreeDTO;
import io.adrainty.bolee.framework.commons.basic.TreeItemDTO;
import io.adrainty.bolee.framework.commons.exception.AppException;
import io.adrainty.bolee.framework.commons.utils.IdentifierNoUtil;
import io.adrainty.bolee.framework.commons.utils.TreeItemUtil;
import io.adrainty.bolee.security.models.constants.DeptConstants;
import io.adrainty.bolee.security.models.entity.DeptEntity;
import io.adrainty.bolee.security.repository.IDeptRepository;
import io.adrainty.bolee.security.service.IDeptService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * <p>DeptServiceImpl</p>
 *
 * @author AdRainty
 * @version V1.0.0
 * @description IDeptService
 * @since 2025/8/7 13:49:46
 */

@Slf4j
@Service
public class DeptServiceImpl implements IDeptService {

    @Resource
    private IDeptRepository deptRepository;

    @Override
    @Transactional
    @Caching(
            evict = {
                    @CacheEvict(value = DeptConstants.PAGE, allEntries = true),
                    @CacheEvict(value = DeptConstants.TREE, allEntries = true),
                    @CacheEvict(value = DeptConstants.LIST, allEntries = true)},
            put = {
                    @CachePut(value = DeptConstants.BASIC, key = "#result.id")
            }
    )
    public DeptEntity createDept(DeptEntity deptEntity) {
        if (StringUtils.isBlank(deptEntity.getParentDeptNo())) {
            deptEntity.setParentDeptNo(IdentifierNoUtil.ROOT_PARENT_ID);
        }
        
        String currentDeptNo = createDeptNo(deptEntity.getCompanyNo(), deptEntity.getParentDeptNo());
        deptEntity.setDeptNo(currentDeptNo);
        boolean result = deptRepository.save(deptEntity);
        if (!result) {
            throw new AppException(ResponseCode.DEPT_CREATE_ERROR);
        }
        return deptEntity;
    }

    @Override
    public List<DeptEntity> findDeptList(DeptEntity entity) {
        return deptRepository.findDeptList(entity);
    }

    @Override
    public IPage<DeptEntity> pageDept(Integer pageNum, Integer pageSize, DeptEntity deptEntity) {
        return deptRepository.pageDept(pageNum, pageSize, deptEntity);
    }

    @Override
    public Boolean updateDept(DeptEntity entity) {
        if (entity.getId() == null) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        }
        return deptRepository.updateDept(entity);
    }

    @Override
    public TreeDTO findDeptTree(DeptEntity entity) {
        String parentDeptNo = StringUtils.defaultIfBlank(entity.getParentDeptNo(), IdentifierNoUtil.ROOT_PARENT_ID);
        List<DeptEntity> deptEntities = deptRepository.findSubDeptList(parentDeptNo);
        if (CollUtil.isEmpty(deptEntities)) {
            throw new AppException(ResponseCode.DEPT_NOT_FOUND);
        }

        List<String> checkedIds = entity.getCheckedDeptNos() == null? List.of() :
                Arrays.stream(entity.getCheckedDeptNos()).toList();
        List<String> expandedIds = new ArrayList<>();
        // 下面Contains要用 转为Set加快效率
        Set<String> checkedIdSet = new HashSet<>(checkedIds);
        List<TreeItemDTO> treeItemDTOList = deptEntities.stream().map(dept -> {
            TreeItemDTO treeItemDTO = TreeItemDTO.builder()
                    .id(dept.getDeptNo())
                    .parentId(dept.getParentDeptNo())
                    .label(dept.getDeptName())
                    .isChecked(checkedIdSet.contains(dept.getDeptNo()))
                    .build();
            // 展开项, 默认展开为二级
            // 如果为100_001_001_000_000 > 100_001_001 才展开
            // 如果为100_001_001_001_000 > 100_001_001_001 就不展开
            if (IdentifierNoUtil.processNo(dept.getDeptNo()).length() / 3 == 3) {
                expandedIds.add(dept.getDeptNo());
            }
            return treeItemDTO;
        }).toList();

        return TreeItemUtil.returnTreeDTO(checkedIds, expandedIds, parentDeptNo, treeItemDTOList);
    }

    private String createDeptNo(String companyNo, String parentDeptNo) {
        List<DeptEntity> deptBOList = deptRepository.findSubLevel1DeptList(companyNo, parentDeptNo);
        if (CollUtil.isEmpty(deptBOList)) {
            return IdentifierNoUtil.createNo(parentDeptNo, false);
        } else {
            return deptBOList.stream()
                    .map(dept -> Long.valueOf(dept.getDeptNo()))
                    .max(Comparator.comparing(i -> i))
                    .map(String::valueOf)
                    .map(i -> IdentifierNoUtil.createNo(i, true))
                    .orElse(IdentifierNoUtil.createNo(parentDeptNo, false));
        }
    }

}
